import mimetypes,os,stat

from django.conf              import settings
from django.core.urlresolvers import reverse
from django.http              import Http404,HttpResponse,HttpResponseNotModified
from django.template          import loader,RequestContext
from django.utils._os         import safe_join
from django.utils.http        import http_date
from django.utils.importlib   import import_module
from django.views.static      import was_modified_since
from sitepal.sitetheme.models import Theme

if settings.DEBUG:
    import sys,traceback

STYLESHEET_TAG_TYPE = 'link'
STYLESHEET_TAG      = '<link rel="stylesheet" type="text/css" media="{tag_media}" href="{url}"/>'
STYLESHEET          = {'tag':STYLESHEET_TAG,'tag_type':STYLESHEET_TAG_TYPE}
STYLESHEET_ALL      = {'tag':STYLESHEET_TAG,'tag_type':STYLESHEET_TAG_TYPE,'tag_media':'all'}
JAVASCRIPT_TAG_TYPE = 'script'
JAVASCRIPT_TAG      = '<script type="text/javascript" src="{url}"></script>'
JAVASCRIPT          = {'tag':JAVASCRIPT_TAG,'tag_type':JAVASCRIPT_TAG_TYPE}

class Medium(object):
    def __init__(self,path,name,tag=None,tag_type=None,tag_media=None):
        mimetype,encoding = mimetypes.guess_type(name)
        assert mimetypes.guess_extension(mimetype)
        self.mimetype  = mimetype
        self.theme     = None
        self.tag       = tag
        self.tag_type  = tag_type
        self.tag_media = tag_media
        self.name      = self.sanatize_name(name)
        self.url       = None
        if not isinstance(path,basestring):
            module = path
            if module.__name__.rfind('.siteapp') == -1:
                raise ValueError,"Path must be either a string or the siteapp module"
            module_name = ".".join((module.__name__,'theme'))
            try:
                module = import_module(module_name)
                path   = os.path.normpath(os.path.join(os.path.dirname(module.__file__),'media'))
                if not os.path.isdir(path):
                    raise ValueError,"Must be an existing directory: {0}".format(path)
            except ImportError:
                raise ValueError,"Module '{0}' does not implement a theme".format(path.__name__)
        self.filename = self.sanatize_filename(path)

    def __repr__(self):
        return "<{0}: {1}>".format(self.__class__.__name__,self.__str__())

    def __str__(self):
        return "{0} ({1})".format(self.name,self.mimetype)

    def theme_setup(self,theme):
        assert(isinstance(theme,Theme))
        self.theme = theme
        self.url   = reverse('theme_media',kwargs={'name':self.name,'theme':theme.name})
        self.tag   = self.tag.format(**self.__dict__) if self.tag else None

    def sanatize_name(self,name):
        if not isinstance(name,basestring):
            raise ValueError,"name must be a string"
        name = name.lstrip('/')
        for extension in mimetypes.guess_all_extensions(self.mimetype):
            if name.endswith(extension):
                return name
        raise ValueError,"invalid name: '{0}'".format(name)

    def sanatize_filename(self,path):
        filename = safe_join(path,self.name)
        if not isinstance(filename,basestring):
            raise ValueError,"fileame must be a string"
        if not os.path.isabs(filename):
            raise ValueError,"fileame must be have an absolute path"
        if not os.path.isfile(filename):
            raise ValueError,"fileame must be an existing file"
        return filename

    def was_modified_since(self,request,statobj):
        return was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                                  statobj[stat.ST_MTIME],statobj[stat.ST_SIZE])

    def load_medium(self,request):
        raise NotImplementedError

    def get_response(self,request):
        try:
            statobj = os.stat(self.filename)
            if self.was_modified_since(request,statobj):
                contents = self.load_medium(request)
                response = HttpResponse(contents,mimetype=self.mimetype)
                response["Last-Modified"]  = http_date(statobj[stat.ST_MTIME])
                response["Content-Length"] = len(contents)
                return response
            return HttpResponseNotModified(mimetype=self.mimetype)
        except Exception,e:
            if settings.DEBUG:
                traceback.print_exception(*sys.exc_info(),limit=2,file=sys.stdout)
            raise

class DirectMedium(Medium):
    def load_medium(self,request):
        with open(self.filename,'rb') as medium:
            return medium.read()

class TemplateMedium(Medium):
    def load_medium(self,request):
        from sitepal.sitetheme.models import Theme
        
        with open(self.filename,'rb') as medium:
            source = medium.read()
        context  = RequestContext(request,{'theme':Theme.objects.get_current()})
        template = loader.get_template_from_string(source)
        return template.render(context)

class ApplicationTemplate(TemplateMedium):
    def __init__(self,path,name):
        super(ApplicationTemplate,self).__init__(path,name)

    def theme_setup(self,theme):
        super(ApplicationTemplate,self).theme_setup(theme)
        self.url = None

    def get_response(self,request):
        raise Http404

